package com.password.secure;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;

import com.password.util.RSAEncryptUtil;

public class SecretSign {

	/**
	 * 获取签名的类
	 * <li>{@code SHA1withDSA}</li>
	 * <li>{@code SHA1withRSA}</li>
	 * <li>{@code SHA256withRSA}</li>
	 * @author yzh
	 * @throws Exception 
	 * @throws NoSuchAlgorithmException 
	 * @date 2020年6月1日
	 *
	 */
	public static SignObject getSignObject(String algorithm, byte[] privateKey) throws Exception {
		return new SignObject(algorithm, privateKey);
	}

	/**
	 * 会自动生成公钥秘钥对
	 * @author yzh
	 * @date 2020年6月1日
	 *  
	 * @return
	 * @throws Exception
	 */
	public static SignObject getSignObject() throws Exception {
		return new SignObject("SHA256withRSA");
	}

	/**
	 * 获取验签类
	 * <li>{@code SHA1withDSA}</li>
	 * <li>{@code SHA1withRSA}</li>
	 * <li>{@code SHA256withRSA}</li>
	 * @author yzh
	 * @throws Exception 
	 * @throws NoSuchAlgorithmException 
	 * @date 2020年6月1日
	 *
	 */
	public static VerifyObject getVerifyObject(String algorithm, byte[] publicKey) throws Exception {
		return new VerifyObject(algorithm, publicKey);
	}

	public static VerifyObject getVerifyObject(byte[] publicKey) throws Exception {
		return new VerifyObject("SHA256withRSA", publicKey);
	}

	/**
	 * 用于签名
	 * @author yzh
	 * @date 2020年6月1日
	 *
	 */
	public static class SignObject {

		private final Signature signature;

		private final byte[] publicKey;

		/**
		 * 会自动生成公钥私钥对，RSA的公钥私钥对
		 * @param algorithm
		 * @throws Exception
		 */
		public SignObject(String algorithm) throws Exception {
			signature = Signature.getInstance(algorithm);
			Map<Integer, String> genKeyPair = RSAEncryptUtil.genKeyPair();
			publicKey = Base64.getDecoder().decode(genKeyPair.get(0));
			byte[] privateKey = Base64.getDecoder().decode(genKeyPair.get(1));
			RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA")
					.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
			signature.initSign(priKey);
		}

		/**
		 * 签名
		 * <li>{@code SHA1withDSA}</li>
		 * <li>{@code SHA1withRSA}</li>
		 * <li>{@code SHA256withRSA}</li>
		 * @author yzh
		 * @throws NoSuchAlgorithmException 
		 * @date 2020年6月1日
		 *
		 */
		public SignObject(String algorithm, byte[] privateKey) throws Exception {
			signature = Signature.getInstance(algorithm);
			publicKey = null;
			RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA")
					.generatePrivate(new PKCS8EncodedKeySpec(privateKey));
			signature.initSign(priKey);
		}

		/**
		 * 
		 * @author yzh
		 * @date 2020年6月1日
		 *  
		 * @param data
		 * @throws SignatureException
		 */
		public void update(byte[] data, int offSet, int len) throws SignatureException {
			signature.update(data, offSet, len);
		}

		/**
		 * 完成签名
		 * @author yzh
		 * @date 2020年6月1日
		 *  
		 * @return
		 * @throws SignatureException
		 */
		public byte[] sign() throws SignatureException {
			return signature.sign();
		}

		public byte[] getPublicKey() {
			return publicKey;
		}

	}

	/**
	 * 用于校验
	 * @author yzh
	 * @date 2020年6月1日
	 *
	 */
	public static class VerifyObject {
		private final Signature signature;

		/**
		 * 签名
		 * <li>{@code SHA1withDSA}</li>
		 * <li>{@code SHA1withRSA}</li>
		 * <li>{@code SHA256withRSA}</li>
		 * @author yzh
		 * @throws NoSuchAlgorithmException 
		 * @date 2020年6月1日
		 *
		 */
		public VerifyObject(String algorithm, byte[] publicKey) throws Exception {
			signature = Signature.getInstance(algorithm);
			RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
					.generatePublic(new X509EncodedKeySpec(publicKey));
			signature.initVerify(pubKey);
		}

		/**
		 * 
		 * @author yzh
		 * @date 2020年6月1日
		 *  
		 * @param data
		 * @throws SignatureException
		 */
		public void update(byte[] data, int offSet, int len) throws SignatureException {
			signature.update(data, offSet, len);
		}

		/**
		 * 完成校验
		 * @author yzh
		 * @date 2020年6月1日
		 *  
		 * @return
		 * @throws SignatureException
		 */
		public boolean verify(byte[] signatureD, int offset, int length) throws SignatureException {
			return signature.verify(signatureD, offset, length);
		}

	}

}
